package com.yanqu.road.server.gameplayer.module.activity.doublespring;

import com.yanqu.road.dao.impl.activity.doublespring.DoubleSpringZlUserDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ActivityValueParamArgs;
import com.yanqu.road.entity.activity.doublespring.DoubleSpringActivityConfig;
import com.yanqu.road.entity.activity.doublespring.data.DoubleSpringZlUserData;
import com.yanqu.road.entity.activity.doublespring.enums.DoubleSpringLogInviteTypeEnum;
import com.yanqu.road.entity.activity.doublespring.enums.DoubleSpringZlTypeEnum;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.MallInfo;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eShopType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.doublespring.LogActivityDoubleSpringBeInvite;
import com.yanqu.road.entity.log.doublespring.LogActivityDoubleSpringExp;
import com.yanqu.road.entity.log.doublespring.LogActivityDoubleSpringInvite;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.activity.DoubleSpringProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.pb.userinfo.UserInfoProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.player.PreReduceModule;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.doublespring.DoubleSpringActivityMgr;
import com.yanqu.road.server.manger.activity.doublespring.pb.DoubleSpringActivityPb;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.union.UnionMgr;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.sync.message.SyncResponse;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

public class DoubleSpringActivityModule extends GeneralModule {

    //购买战令礼包数据。k:活动ID
    private Map<Integer, DoubleSpringZlUserData> zlMallDataMap = new ConcurrentHashMap<>();

    //出行并发锁
    private final Object travelLock = new Object();

    public DoubleSpringActivityModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.DoubleSpring.getValue());
        for (ActivityInfo activityInfo : activityList) {
            DoubleSpringZlUserData data = new DoubleSpringZlUserDataDaoImpl().getDoubleSpringZlUserData(activityInfo.getActivityId(), this.getUserId());
            if (data != null) {
                zlMallDataMap.put(data.getActivityId(), data);
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public void afterLogin() {
        this.syncMsg();
    }

    /**
     * 同步下数据
     */
    public void syncMsg() {
        //判断系统是否解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.DoubleSpring.getValue())) {
            return;
        }
        //同步
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.DoubleSpring.getValue());
        for (ActivityInfo info : activityList) {
            //同步战令数据
            DoubleSpringZlUserData data = this.zlMallDataMap.get(info.getActivityId());
            this.syncZjData(info.getActivityId(), data);
            //同步积分数据
            DoubleSpringProto.DoubleSpringSyncUserDataServerToCross.Builder builder = DoubleSpringProto.DoubleSpringSyncUserDataServerToCross.newBuilder();
            builder.setActivityId(info.getActivityId());
            player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_SYNC_USER_DATA, builder);
        }
    }

    @Override
    public boolean saveData() {
        for (DoubleSpringZlUserData data : this.zlMallDataMap.values()) {
            if (data.isInsertOption()) {
                new DoubleSpringZlUserDataDaoImpl().add(data);
            } else if (data.isUpdateOption()) {
                new DoubleSpringZlUserDataDaoImpl().update(data);
            }
        }
        return true;
    }

    /**
     * 同步玩家数据（单人同行）
     * @param data
     */
    public void syncZjData(int activityId, DoubleSpringZlUserData data) {
        DoubleSpringProto.DoubleSpringPlayerZlData.Builder builder = DoubleSpringActivityPb.buildPlayerZlData(activityId, data);
        DoubleSpringProto.DoubleSpringUserDataOneSyncMsg.Builder msg = DoubleSpringProto.DoubleSpringUserDataOneSyncMsg.newBuilder();
        msg.setZlData(builder);
        player.sendPacket(Protocol.U_DOUBLE_SPRING_USER_DATA_ONE_SYNC, msg);
    }

    /**
     * 购买战力礼包后处理（存储购买记录）
     * @param mallInfo
     */
    public void afterBuyZlMallHandle(MallInfo mallInfo) {
        DoubleSpringZlUserData zlMallData = this.getOrCreateDoubleSpringZlUserData(mallInfo.getActivityId());
        //判断是哪个礼包
        if (mallInfo.getShopType() == eShopType.DoubleSpringZlBysf.getValue()) {
            zlMallData.setBysfMallId(mallInfo.getMallId());
        } else if (mallInfo.getShopType() == eShopType.DoubleSpringZlQbjj.getValue()) {
            zlMallData.setQbjjMallId(mallInfo.getMallId());
        }
        //通知一下任务监听
        ActivityValueParamArgs args = new ActivityValueParamArgs(zlMallData.getActivityId(), zlMallData.getExp(), "");
        player.notifyListener(eGamePlayerEventType.DoubleSpringZl.getValue(), args);
        //同步一下
        this.syncZjData(zlMallData.getActivityId(), zlMallData);
    }

    /**
     * 增加经验
     * @param exp
     */
    public void addExp(long exp) {
        List<ActivityInfo> activityList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.DoubleSpring.getValue());
        for (ActivityInfo activityInfo : activityList) {
            if (!ActivityHelper.activityInTime(activityInfo)) {
                continue;
            }
            synchronized (this) {
                //获取玩家数据
                DoubleSpringZlUserData zlUserData = this.getOrCreateDoubleSpringZlUserData(activityInfo.getActivityId());
                //增加经验
                long userExp = zlUserData.getExp() + exp;
                zlUserData.setExp(userExp);
            }
            //任务通知
            DoubleSpringZlUserData zlUserData = this.getDoubleSpringZlUserData(activityInfo.getActivityId());
            long userExp = zlUserData.getExp();
            ActivityValueParamArgs args = new ActivityValueParamArgs(activityInfo.getActivityId(), userExp, "");
            player.notifyListener(eGamePlayerEventType.DoubleSpringZl.getValue(), args);
            //同步下战令数据
            this.syncZjData(zlUserData.getActivityId(), zlUserData);
            //日志
            LogActivityDoubleSpringExp log = new LogActivityDoubleSpringExp();
            log.setActivityId(activityInfo.getActivityId());
            log.setUserId(this.getUserId());
            log.setAddExp(exp);
            log.setExp(userExp);
            log.setCreateTime(System.currentTimeMillis());
            AutoLogMgr.add(log);
        }
    }

    /**
     * 获取战令玩家数据，不存在创建
     * @param activityId
     * @return
     */
    private synchronized DoubleSpringZlUserData getOrCreateDoubleSpringZlUserData(int activityId) {
        DoubleSpringZlUserData zlMallData = zlMallDataMap.get(activityId);
        if (zlMallData == null) {
            zlMallData = new DoubleSpringZlUserData();
            zlMallData.setActivityId(activityId);
            zlMallData.setUserId(this.getUserId());
            zlMallData.setExp(0);
            zlMallData.setBysfMallId(0);
            zlMallData.setBysfMallId(0);
            zlMallData.setCreateTime(System.currentTimeMillis());
            zlMallData.setInsertOption();
            zlMallDataMap.put(activityId, zlMallData);
        }
        return zlMallData;
    }

    /**
     * 获取玩家战令数据
     * @param activityId
     * @return
     */
    private DoubleSpringZlUserData getDoubleSpringZlUserData(int activityId) {
        return zlMallDataMap.get(activityId);
    }

    /**
     * 判断战力礼包是否购买
     * @param activityId
     * @param zlType
     * @return
     */
    public boolean checkZlMallBuy(int activityId, int zlType) {
        DoubleSpringZlUserData zlMallData = this.zlMallDataMap.get(activityId);
        if (zlMallData == null) {
            return false;
        }
        if (zlType == DoubleSpringZlTypeEnum.DOUBLE_SPRING_ZL_TYPE_BYSF.getType()) {
            if (zlMallData.getBysfMallId() > 0) {
                return true;
            }
        }
        if (zlType == DoubleSpringZlTypeEnum.DOUBLE_SPRING_ZL_TYPE_QBJJ.getType()) {
            if (zlMallData.getQbjjMallId() > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 通用校验
     * @throws BusinessException
     */
    private void checkCommon(int activityId, long targetServer) throws BusinessException {
        //判断活动
        ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
        if (activityInfo == null) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_ACTIVITY_NOT_EXIST);
        }
        //判断是否在活动进行期
        if (!ActivityHelper.activityInTime(activityInfo)) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_ACTIVITY_NOT_IN_TIME);
        }
        //系统是否解锁
        if (!SystemOpenMgr.checkSystemOpen(this.getUserId(), eSystemId.DoubleSpring.getValue())) {
            throw BusinessException.newException(GameErrorCode.E_SYSTEM_NO_OPEN);
        }
        //判断活动是否包含对方区服
        DoubleSpringActivityConfig config = DoubleSpringActivityMgr.getActivityConfig(activityId);
        if (config == null) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_ACTIVITY_CONFIG_NOT_EXIST);
        }
        if (targetServer > 0 && !config.getActivityInfo().getServerIdList().contains(targetServer)) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_TARGET_USER_SERVER_NOT_IN_ACTIVITY);
        }
    }

    /*************************************************CMD********************************/

    /**
     * 邀请玩家
     * @param reqMsg
     * @throws BusinessException
     */
    public void inviteUser(DoubleSpringProto.DoubleSpringInviteUserReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), reqMsg.getServerId());
        //不能邀请自己
        if (getUserId() == reqMsg.getUserId()) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_NOT_INVITE_SELF);
        }

        //跨服req
        DoubleSpringProto.DoubleSpringServerToCrossInviteUserReqMsg.Builder builder = DoubleSpringProto.DoubleSpringServerToCrossInviteUserReqMsg.newBuilder();
        builder.setActivityId(reqMsg.getActivityId());
        builder.setUserId(reqMsg.getUserId());
        builder.setServerId(reqMsg.getServerId());
        UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(this.getUserId(), GameServer.getInstance().getServerId());
        if (userBaseInfo != null) {
            //带上userBaseInfo到跨服
            builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        }

        //判断玩家是否存在
        if (reqMsg.getServerId() == GameServer.getInstance().getServerId()) {
            //本服
            UserBaseInfo targetUserBaseInfo = UserMgr.getUserBaseInfo(reqMsg.getUserId(), reqMsg.getServerId());
            if (targetUserBaseInfo == null) {
                throw BusinessException.newException(GameErrorCode.E_USER_NO_FOUND);
            }
            //带上userBaseInfo到跨服
            builder.setTargetPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(targetUserBaseInfo));
            //发送到跨服
            player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_INVITE_USER, builder);
        } else {
            //非本区服，跨服查询
            UserInfoProto.UserInfoDetailReqMsg.Builder queryReqMsg = UserInfoProto.UserInfoDetailReqMsg.newBuilder();
            queryReqMsg.setUserId(reqMsg.getUserId());
            queryReqMsg.setServerId(reqMsg.getServerId());
            UserInfoProto.UserInfoDetailRespMsg.Builder queryRespMsg = UserInfoProto.UserInfoDetailRespMsg.newBuilder();
            CompletableFuture<SyncResponse> responseFuture = GamePlayerMgr.sendToGameServer(reqMsg.getServerId(), GameProtocol.S_USER_INFO_DETAIL_SERVICE, player.getUserId(), queryReqMsg, queryRespMsg);
            responseFuture.thenAccept(syncResponse -> {
                if (syncResponse.getErrorCode() == 0) {
                    if (queryRespMsg.getRet() == 0) {
                        //带上userBaseInfo到跨服
                        builder.setTargetPlayerBaseData(queryRespMsg.getInfo());
                        //发送到跨服
                        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_INVITE_USER, builder);
                    } else {
                        DoubleSpringProto.DoubleSpringInviteUserRespMsg.Builder respMsg = DoubleSpringProto.DoubleSpringInviteUserRespMsg.newBuilder();
                        respMsg.setRet(queryRespMsg.getRet());
                        player.sendPacket(Protocol.U_DOUBLE_SPRING_INVITE_USER, respMsg);
                    }
                } else {
                    DoubleSpringProto.DoubleSpringInviteUserRespMsg.Builder respMsg = DoubleSpringProto.DoubleSpringInviteUserRespMsg.newBuilder();
                    respMsg.setRet(GameErrorCode.E_ERROR_TIME_OUT);
                    player.sendPacket(Protocol.U_DOUBLE_SPRING_INVITE_USER, respMsg);
                }
            });
        }
    }

    /**
     * 获取已邀请列表
     * @param reqMsg
     * @throws BusinessException
     */
    public void getInviteList(DoubleSpringProto.DoubleSpringGetInviteUserListReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), 0);
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_INVITE_LIST, reqMsg.toBuilder());
    }

    /**
     * 获取被邀请列表
     * @param reqMsg
     * @throws BusinessException
     */
    public void getReceivedInviteList(DoubleSpringProto.DoubleSpringGetReceivedInviteListReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), 0);
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_RECEIVED_INVITE_LIST, reqMsg.toBuilder());
    }

    /**
     * 取消邀请
     * @param reqMsg
     * @throws BusinessException
     */
    public void cancelInvite(DoubleSpringProto.DoubleSpringCancelInviteUserReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), reqMsg.getServerId());
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_CANCEL_INVITE, reqMsg.toBuilder());
    }

    /**
     * 同意邀请
     * @param reqMsg
     * @throws BusinessException
     */
    public void agreeInvite(DoubleSpringProto.DoubleSpringAgreeInviteReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), reqMsg.getServerId());
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_AGREE_INVITE, reqMsg.toBuilder());
    }

    /**
     * 拒绝邀请
     * @param reqMsg
     * @throws BusinessException
     */
    public void rejectInvite(DoubleSpringProto.DoubleSpringRejectInviteReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), 0);
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_REJECT_INVITE, reqMsg.toBuilder());
    }

    /**
     * 出行
     * @param reqMsg
     * @throws BusinessException
     */
    public void travel(DoubleSpringProto.DoubleSpringTravelReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), 0);
        //获取活动配置
        DoubleSpringActivityConfig doubleSpringActivityConfig = DoubleSpringActivityMgr.getActivityConfig(reqMsg.getActivityId());
        if (doubleSpringActivityConfig == null) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_ACTIVITY_CONFIG_NOT_EXIST);
        }
        synchronized (this.travelLock) {
            //道具消耗
            Property property = doubleSpringActivityConfig.getDoubleSpringItemCost();
            //判断道具是否足够
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(property)) {
                throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_ACTIVITY_PROP_NOT_ENOUGH);
            }
            //扣道具
            player.getModule(PreReduceModule.class).preReduce(property);
        }
        //带上userBaseInfo到跨服
        DoubleSpringProto.DoubleSpringServerToCrossTravelReqMsg.Builder builder = DoubleSpringProto.DoubleSpringServerToCrossTravelReqMsg.newBuilder();
        builder.setActivityId(reqMsg.getActivityId());
        UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(this.getUserId(), GameServer.getInstance().getServerId());
        if (userBaseInfo != null) {
            builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        }
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_TRAVEL, builder);
    }

    /**
     * 获取玩家积分
     * @param reqMsg
     * @throws BusinessException
     */
    public void getUserScore(DoubleSpringProto.DoubleSpringGetScoreReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), 0);
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_GET_SCORE, reqMsg.toBuilder());
    }

    /**
     * 查询玩家
     * @param reqMsg
     * @throws BusinessException
     */
    public void queryUser(DoubleSpringProto.DoubleSpringQueryUserReqMsg reqMsg) throws BusinessException {
        //通用校验
        this.checkCommon(reqMsg.getActivityId(), reqMsg.getServerId());
        long queryUserAliasId = reqMsg.getUserId();
        //不能查询自己
        if (player.getUserInfo().getUserAliasId() == queryUserAliasId) {
            throw BusinessException.newException(GameErrorCode.E_DOUBLE_SPRING_NOT_QUERY_SELF);
        }

        DoubleSpringProto.DoubleSpringServerToCrossQueryUserReqMsg.Builder builder = DoubleSpringProto.DoubleSpringServerToCrossQueryUserReqMsg.newBuilder();
        builder.setActivityId(reqMsg.getActivityId());
        builder.setUserAliasId(queryUserAliasId);
        builder.setServerId(reqMsg.getServerId());
        //判断是本服。还是跨服
        if (reqMsg.getServerId() == GameServer.getInstance().getServerId()) {
            //带上userBaseInfo
            UserInfo userInfo = UserMgr.getUserInfoByAliasId(queryUserAliasId);
            if (userInfo != null) {
                UserBaseInfo userBaseInfo = UserMgr.parseUserBaseInfo(userInfo, reqMsg.getServerId());
                if (userBaseInfo != null) {
                    builder.setUserId(userInfo.getUserId());
                    builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                }
            }
        }
        //发送到跨服
        player.sendPacket(Protocol.C_CROSS_DOUBLE_SPRING_QUERY_USER, builder);
    }

    /**
     * 更新出游积分
     * @param activityId
     * @param travelScore
     */
    public void updateTravelScore(int activityId, long travelScore) {
        //通知condition
        ActivityValueParamArgs args = new ActivityValueParamArgs(activityId, travelScore, "");
        player.notifyListener(eGamePlayerEventType.DoubleSpringScore.getValue(), args);
    }
}
